﻿using MemorySiteServer.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace MemorySiteServer.AuthManage
{
    public class JwtServer
    {
        public const string Issuer = "MemorySiteServer";
        public const string SecurityKey = "c0cc0dfdfaef2370e4d56711175fe349def6ed4cba25d3c7a01fc6ef6568220d";
        private static readonly List<UserAudience> UserAudiences = new List<UserAudience>();
        private static readonly List<UserCode> UserCodes = new List<UserCode>();

        #region UserAudience，TOKEN

        /// <summary>
        /// 获取用户所拥有的权限列表
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public static List<RolePermission> GetUserPermissions(long userID)
        {
            var rolePermissions = new List<RolePermission>();
            var userAudience = GetUserAudienceFromServer(userID);
            if (userAudience != null)
                rolePermissions.AddRange(userAudience.User.Role.RolePermissions);
            return rolePermissions;
        }

        public static User GetUser(long userID)
        {
            var userAudience = GetUserAudienceFromServer(userID);
            if (userAudience != null)
                return userAudience.User;
            else
                return null;
        }

        /// <summary>
        /// 获取UserAudiences
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public static UserAudience GetUserAudienceFromServer(long userID)
        {
            return UserAudiences.FirstOrDefault(x => x.User.ID == userID);
        }

        /// <summary>
        /// 更新缓存的用户角色，用于修改角色之后
        /// </summary>
        /// <param name="role"></param>
        public static void UpdateRole(Role role)
        {
            UserAudiences.ForEach(x =>
            {
                if (x.User.RoleID == role.ID)
                    x.User.Role = role;
            });
        }

        /// <summary>
        /// 替换用户的角色，通常用于删除角色后替换为游客
        /// </summary>
        /// <param name="originalRoleID"></param>
        /// <param name="role"></param>
        public static void ReplaceRole(long originalRoleID,Role role)
        {
            UserAudiences.ForEach(x => { 
                if(x.User.RoleID == originalRoleID)
                {
                    x.User.RoleID = role.ID;
                    x.User.Role = role;
                }
            });
        }

        /// <summary>
        /// 添加或更新Audience，用于其他端登录用户下线或持久化Token
        /// </summary>
        /// <param name="userAudience"></param>
        /// <param name="dataContext"></param>
        /// <returns></returns>
        public async static Task AddOrUpdateUserAudience(UserAudience userAudience, DbContext dataContext)
        {
            var dbUserAudience = GetUserAudienceFromServer(userAudience.User.ID);
            if (dbUserAudience == null)
            {
                await userAudience.AddUserAudience(dataContext);
                UserAudiences.Add(userAudience);
            }
            else
            {
                dbUserAudience.ServerAudience = userAudience.ServerAudience;
                await dbUserAudience.UpdataUserAudience(dataContext);
            }
        }

        /// <summary>
        /// 用于程序初始化时从数据库载入所有的权限
        /// </summary>
        /// <param name="userAudiences"></param>
        public static void InitUserAudiences(List<UserAudience> userAudiences)
        {
            UserAudiences.AddRange(userAudiences);
        }

        /// <summary>
        /// 验证用户所持有的TOKEN是否已经失效
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="Audience"></param>
        /// <returns></returns>
        public static bool VerifyUserAudience(int userID, string Audience)
        {
            return UserAudiences.Any(x => x.UserID == userID && x.ServerAudience == Audience);
        }
        /// <summary>
        /// 颁发TOKEN证书
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="audience"></param>
        /// <param name="expiresTime"></param>
        /// <returns></returns>
        public static string GetToken(string userID, string audience, DateTime expiresTime)
        {
            var claims = new[]
{
                new Claim("name", userID),
            };
            //sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtServer.SecurityKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
            var token = new JwtSecurityToken(
                //颁发者
                issuer: JwtServer.Issuer,
                //接收者
                audience: audience,
                //过期时间
                expires: expiresTime,
                //签名证书
                signingCredentials: creds,
                //自定义参数
                claims: claims
                );
            return "Bearer " + new JwtSecurityTokenHandler().WriteToken(token);
        }

        #endregion

        #region 验证码UserCode

        /// <summary>
        /// 将userCode添加到队列，等待验证
        /// </summary>
        /// <param name="userCode"></param>
        public static void AddUserCode(UserCode userCode)
        {
            CullExpiredUserCodes();
            userCode.ServerCode = userCode.ServerCode;
            UserCodes.Add(userCode);
        }

        /// <summary>
        /// 获取服务器端的UserCode
        /// </summary>
        /// <param name="clientID"></param>
        /// <returns></returns>
        public static List<UserCode> GetUserCode(string clientID)
        {
            return UserCodes.Where(x => x.ClientID == clientID).ToList();
        }

        /// <summary>
        /// 检查clientID和验证码
        /// </summary>
        /// <param name="clientID"></param>
        /// <param name="code"></param>
        /// <returns>0-clientID错误；1-code错误；2验证通过</returns>
        public static int VerifyUserCode(string clientID, string code)
        {
            CullExpiredUserCodes();
            int status = 0;
            var userCodes = GetUserCode(clientID);
            if (userCodes.Count > 0)
            {
                UserCode userCode = userCodes.FirstOrDefault(x => x.ServerCode == code.ToUpperInvariant());
                bool isFound = userCode != null;
                if (isFound)
                    status = 2;
                else
                    status = 1;
            }
            return status;
        }

        /// <summary>
        /// 用于登陆后移除已验证的UserCode
        /// </summary>
        /// <param name="clientID"></param>
        /// <param name="code"></param>
        public static void RemoveUserCode(string clientID, string code)
        {
            UserCodes.RemoveAll(x => x.ClientID == clientID && x.ServerCode == code.ToUpperInvariant());
        }

        /// <summary>
        /// 移除所有10分钟前生成的验证码，主要是回收资源
        /// </summary>
        private static void CullExpiredUserCodes()
        {
            UserCodes.RemoveAll(x => (DateTime.Now - x.BuildTime).TotalMinutes > 10);
        }

        #endregion

    }
}
